/* $RCSFile: ModulesLayoutManager.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/Design/ModulesLayoutManager.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:28  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Web.Caching;
using System.Diagnostics;
using System.Collections;
using System.Configuration;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Xml.Serialization;
using System.Text;
using System.IO;
using System.Globalization;

using AddonNice.Configuration;
using AddonNice.Core;
using AddonNice.Helpers;
using AddonNice.Diagnostics;
using AddonNice.Settings.Cache;

namespace AddonNice.Design
{
	// CS 19/3/4 Added error checking and traces
    /// <summary>
    /// The ModulesLayoutManager class encapsulates all data logic necessary to
    /// use differents Layouts across the entire portal.
    /// Manages the Load and Save of the Layout.
    /// Encapsulates a ModulesLayout object that contains all the settings of the current ModulesLayout.
    /// </summary>
	public class ModulesLayoutManager
    {
        string			_portalPath;
        public ModulesLayout CurrentModulesLayout = new ModulesLayout();

        public ModulesLayoutManager(string portalPath)
        {
            _portalPath = portalPath;
        }

		public void ClearCacheList()
		{
			//Clear cache
            CurrentCache.Remove(Key.ModulesLayoutList(Path));
            CurrentCache.Remove(Key.ModulesLayoutList(PortalModulesLayoutPath));
		}

        /// <summary>
        /// Read the Path dir and returns an ArrayList with all the Layouts found.
        /// Static because the list is Always the same.
        /// </summary>
        /// <returns></returns>
        public static ArrayList GetPublicModulesLayouts()
        {
            ArrayList baseModulesLayoutList;
            if ( ModulesLayoutTrace.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]ModulesLayoutManager GetPublicModulesLayouts BEG Path: [{0}]", Path),ModulesLayoutTrace.Sw.Info);

            if (!CurrentCache.Exists(Key.ModulesLayoutList(Path)))
            {
                //Initialize array
                baseModulesLayoutList = new ArrayList();

                string[] Layouts;

                // Try to read directories from public theme path
                try
                {
                    // Try to read directories from public theme path
                    if (Directory.Exists(Path))
                    {
                        Layouts = Directory.GetDirectories(Path);
                    }
                    else
                    {
                        Layouts = new string[0];
                    }

                }
                // CS 19/3/4				
                catch (Exception ex)
                {
                    if ( ModulesLayoutTrace.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager GetPublicModulesLayouts Directory.GetDirectories'{0}' failed, no Layouts to load, ex : {1}", Path, ex),ModulesLayoutTrace.Sw.Info);
                    Layouts = new string[0];
                }

                int len                 =   Path.Length + 1;
                for (int i = 0; i < Layouts.Length; i++)
                {
                    string nm           =   Layouts[i].Substring(len);
                    if ( nm.Equals("CVS") || nm.Equals("_svn") ) //Ignore CVS
                        continue;
                    ModulesLayoutItem t = new ModulesLayoutItem(nm,ItemOrigin.Public);
                    baseModulesLayoutList.Add(t);
                }
                if (baseModulesLayoutList.Count > 0)
                    CurrentCache.Insert(Key.ModulesLayoutList(Path), baseModulesLayoutList);
            }
            else
            {
                baseModulesLayoutList = (ArrayList)CurrentCache.Get(Key.ModulesLayoutList(Path));
            }

            return baseModulesLayoutList;
        }

        /// <summary>
        /// Read the Path dir and returns
        /// an ArrayList with all the Layouts found, public and privates
        /// </summary>
        /// <returns></returns>
        public ArrayList GetPrivateModulesLayouts()
        {
            ArrayList privateLayoutsList;

            if ( ModulesLayoutTrace.Sw.TraceVerbose)
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]ModulesLayoutManager GetPrivateModulesLayouts BEG PortalModulesLayoutPath: [{0}]", PortalModulesLayoutPath),ModulesLayoutTrace.Sw.Info);

            if (!CurrentCache.Exists(Key.ModulesLayoutList(PortalModulesLayoutPath)))
            {

                privateLayoutsList = new ArrayList();
                string[] Layouts;

                // Try to read directories from private theme path
                try
                {
                    if (Directory.Exists(PortalModulesLayoutPath))
                    {
                        Layouts = Directory.GetDirectories(PortalModulesLayoutPath);
                    }

                    else
                    {
                        Layouts = new string[0];
                    }
                }
                // CS 19/3/4				
                catch (Exception ex)
                {
                    if ( ModulesLayoutTrace.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager GetPrivateModulesLayouts Directory.GetDirectories'{0}' failed, no Layouts to load, ex : {1}", Path, ex),ModulesLayoutTrace.Sw.Info);
                    Layouts = new string[0];
                }

                int len                 =   Path.Length + 1;
                for (int i = 0; i <= Layouts.GetUpperBound(0); i++)
                {
                    string nm           =   Layouts[i].Substring(len);
                    if ( nm.Equals("CVS") || nm.Equals("_svn") ) //Ignore CVS
                        continue;
                    ModulesLayoutItem t = new ModulesLayoutItem(nm,ItemOrigin.Portal);
                    privateLayoutsList.Add(t);
                }
                if ( privateLayoutsList.Count > 0 )
                    CurrentCache.InsertLong(Settings.Cache.Key.ModulesLayoutList(PortalModulesLayoutPath), privateLayoutsList, new CacheDependency(PortalModulesLayoutPath));
            }
            else
            {
                privateLayoutsList = (ArrayList)CurrentCache.Get(Key.ModulesLayoutList(PortalModulesLayoutPath));
            }
            return privateLayoutsList;
        }

        /// <summary>
        /// Read the Path dir and returns
        /// an ArrayList with all the Layouts found, public and privates
        /// </summary>
        /// <returns></returns>
        public ArrayList GetModulesLayouts()
        {
            //Initialize array
            ArrayList LayoutsList         =   (ArrayList)GetPublicModulesLayouts().Clone();
            ArrayList LayoutsListPrivate  =   GetPrivateModulesLayouts();
            LayoutsList.AddRange(LayoutsListPrivate);
            return LayoutsList;
        }

        public void Load(string ModulesLayoutsName)
        {
            // CS 19/3/4 security check
            if ( string.IsNullOrEmpty(ModulesLayoutsName))
            {
                if ( ModulesLayoutTrace.Sw.TraceError )
                    Trace.WriteLine( "[E]ModulesLayoutManager Load ModulesLayoutsName null or empty in ModulesLayoutManager.Load, replacing with default",ModulesLayoutTrace.Sw.Info);
                ModulesLayoutsName               = "default";
            }
            // CS 19/3/4 crash avoider!
            ModulesLayout SavedModulesLayout    =   CurrentModulesLayout;
            CurrentModulesLayout                =   new ModulesLayout();
            CurrentModulesLayout.Name           =   ModulesLayoutsName;

            try
            {
                //Try loading portal private Layout first
                if (LoadModulesLayout(Settings.Path.WebPathCombine(PortalWebPath, ModulesLayoutsName)))
                    return;

                //Try loading global Layout
                if (LoadModulesLayout(Settings.Path.WebPathCombine(WebPath, ModulesLayoutsName)))
                    return;

                if ( ModulesLayoutTrace.Sw.TraceInfo )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[I]ModulesLayoutManager Load ModulesLayoutsName: [{0}] Load failed replacing with default", ModulesLayoutsName),ModulesLayoutTrace.Sw.Info);
                //Try default
                CurrentModulesLayout.Name       =   "default";
                if (LoadModulesLayout(AddonNice.Settings.Path.WebPathCombine(WebPath, "default")))
                    return;
            }
            catch (Exception ex)
            {
                if ( ModulesLayoutTrace.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager ModulesLayoutsName'{0}' Load failed, ex : {1} ", ModulesLayoutsName, ex),ModulesLayoutTrace.Sw.Info);
                if (SavedModulesLayout != null)
                    CurrentModulesLayout        =   SavedModulesLayout;
            }
            string errormsg             =   LocalizeHelper.Localize("LOAD_THEME_ERROR");

            if ( ModulesLayoutTrace.Sw.TraceError )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager ModulesLayoutsName'{0}' Load failed", ModulesLayoutsName),ModulesLayoutTrace.Sw.Info);
            throw new FileNotFoundException(errormsg.Replace("%1%", "'" + ModulesLayoutsName + "'"), WebPath + "/" + ModulesLayoutsName);
        }

        public static void OnRemove(string key, object cacheItem, System.Web.Caching.CacheItemRemovedReason reason)
        {
            if ( ModulesLayoutTrace.Sw.TraceInfo )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[I]ModulesLayoutManager OnRemove The cached value with key '{0}' was removed from the cache.  Reason: {1}", key, reason),ModulesLayoutTrace.Sw.Info);
        }

        public void Save(string ModulesLayoutsName)
        {
            CurrentModulesLayout.Name = ModulesLayoutsName;
            CurrentModulesLayout.WebPath = Settings.Path.WebPathCombine(WebPath, ModulesLayoutsName);

            XmlSerializer serializer = new XmlSerializer(typeof(ModulesLayout));

            // Create an XmlTextWriter using a FileStream.
            using (Stream fs = new FileStream(CurrentModulesLayout.ModulesLayoutFileName, FileMode.Create))
            {
                XmlWriter writer = new XmlTextWriter(fs, new UTF8Encoding());
                // CS 19/3/4
                try
                {
                    // Serialize using the XmlTextWriter.
                    serializer.Serialize(writer, CurrentModulesLayout);
                }
                catch (Exception ex)
                {
                    if ( ModulesLayoutTrace.Sw.TraceError )
                        Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager ModulesLayoutsName 3 '{0}' Load failed, ex : {1} ", ModulesLayoutsName, ex),ModulesLayoutTrace.Sw.Info);
                }
                finally
                {
                    if (writer.WriteState != System.Xml.WriteState.Closed)
                        writer.Close();
                }
            }
        }

        
        private bool LoadModulesLayout(string CurrentWebPath)
        {
            if ( ModulesLayoutTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]ModulesLayoutManager LoadModulesLayout BEG CurrentWebPath: [{0}]",CurrentWebPath),ModulesLayoutTrace.Sw.Info);
            // CS 19/3/4 this must be kept here due to ModulesLayoutFileName
            CurrentModulesLayout.WebPath = CurrentWebPath;

            if (!CurrentCache.Exists(Key.CurrentModulesLayout(CurrentWebPath)))
            {
                //Return fail
                if (!File.Exists(CurrentModulesLayout.ModulesLayoutFileName))
                    return false;
                if ( !LoadXml(CurrentModulesLayout.ModulesLayoutFileName))
                    return false;
                CurrentCache.Insert(Key.CurrentModulesLayout(CurrentWebPath), CurrentModulesLayout, new CacheDependency(CurrentModulesLayout.ModulesLayoutFileName));
            }
            else
            {
                CurrentModulesLayout = (ModulesLayout)CurrentCache.Get(Key.CurrentModulesLayout(CurrentWebPath));
            }
            CurrentModulesLayout.WebPath = CurrentWebPath;
            return true;
        }

        /// <summary>
        /// Load an old version xml theme file which contains iamges est webparts and set them in CurrentModulesLayout
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        private bool LoadXml(string filename)
        {
            XmlTextReader _xtr          =   null;
            NameTable _nt               =   new NameTable();
            XmlNamespaceManager _nsm    =   new XmlNamespaceManager(_nt);
            _nsm.AddNamespace(string.Empty, "http://www.w3.org/1999/xhtml");
            XmlParserContext _context   =   new XmlParserContext(_nt, _nsm, string.Empty, XmlSpace.None);
            if ( ModulesLayoutTrace.Sw.TraceVerbose )
                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]ModulesLayoutManager LoadXml filename: {0}", filename),ModulesLayoutTrace.Sw.Info);

            bool returnValue            =   false;
            try
            {
                // Create an XmlTextReader using a FileStream.
                using (Stream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    try
                    {
                        _xtr                                    =   new XmlTextReader(fs, XmlNodeType.Document, _context);
                        _xtr.WhitespaceHandling                 =   WhitespaceHandling.None;

                        ModulesLayoutPart _myPart = new ModulesLayoutPart();

                        while (!_xtr.EOF)
                        {
                            if (_xtr.MoveToContent() == XmlNodeType.Element)
                            {
                                if ( ModulesLayoutTrace.Sw.TraceVerbose )
                                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]ModulesLayoutManager LoadXml LocalName: {0}", _xtr.LocalName),ModulesLayoutTrace.Sw.Info);
                                switch (_xtr.LocalName)
                                {
                                    case StStr.ModuleLayoutName:
                                        CurrentModulesLayout.Name = _xtr.ReadString();
                                        break;

                                    case StStr.ModuleLayoutMinimizeColor:
                                        CurrentModulesLayout.MinimizeColor = _xtr.ReadString();
                                        break;
                                    case StStr.ModuleLayoutParts:
                                    case StStr.ModuleLayoutCss:
                                        break;

                                    case StStr.ModuleLayoutPart:
                                        _myPart                     =   new ModulesLayoutPart();
                                        // search the first attribute 'Name='
                                        while (_xtr.MoveToNextAttribute())
                                        {
                                            switch (_xtr.LocalName)
                                            {
                                                case StStr.ModuleLayoutName:
                                                    _myPart.Name    =   _xtr.Value;
                                                    break;
                                                default:
                                                    break;
                                            }
                                        }
                                        _xtr.MoveToElement();
                                        break;

                                    case StStr.ModuleLayoutPartHTML:
                                        if (_myPart.Name != string.Empty)
                                            _myPart.Html = _xtr.ReadString();
                                        // CS 5/10/04
                                        try
                                        {
                                            // try to replace any image source or background path with real path to this folder
                                            string w        =   string.Concat(CurrentModulesLayout.WebPath, "/");
                                            _myPart.Html    =   _myPart.Html.Replace("src='", string.Concat("src='", w));
                                            _myPart.Html    =   _myPart.Html.Replace("src=\"", string.Concat("src=\"", w));
                                            _myPart.Html    =   _myPart.Html.Replace("background='", string.Concat("background='", w));
                                            _myPart.Html    =   _myPart.Html.Replace("background=\"", string.Concat("background=\"", w));
                                            this.CurrentModulesLayout.ThemeParts.Add(_myPart.Name, _myPart);
                                        }
                                        catch (Exception ex)
                                        {
                                            if ( ModulesLayoutTrace.Sw.TraceError )
                                                Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager LoadXml filename : {0},HTML part : {1},  ex : {2}", filename, _myPart.Name, ex),ModulesLayoutTrace.Sw.Info);
                                        }
                                        break;

                                    default:
                                        if ( ModulesLayoutTrace.Sw.TraceVerbose )
                                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]ModulesLayoutManager LoadXml unwanted filename: {0}, element : [{1}]", filename, _xtr.LocalName),ModulesLayoutTrace.Sw.Info);
                                        break;
                                }
                            }
                            _xtr.Read();
                        }
                        returnValue = true;
                    }
                    catch (Exception ex)
                    {
                        if ( ModulesLayoutTrace.Sw.TraceError )
                            Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager LoadXml filename : {0}, ex : {1}", filename, ex),ModulesLayoutTrace.Sw.Info);
                    }
                    finally
                    {
                        fs.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                if ( ModulesLayoutTrace.Sw.TraceError )
                    Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]ModulesLayoutManager LoadXml filename : {0}, ex : {1}", filename, ex),ModulesLayoutTrace.Sw.Info);
                throw;
            }
            return returnValue;
        }

        /// <summary>
		/// The path of the ModulesLayout dir (Web side)
		/// used to reference images
		/// </summary>
		public static string WebPath
		{
			get
			{
				return AddonNice.Settings.Path.WebPathCombine(AddonNice.Settings.Path.ApplicationRoot,StStr.ModulesLayoutGlobalFolder);
			}
		}
        
		/// <summary>
		/// The path of the current portal ModulesLayout dir (Web side)
		/// used to reference images
		/// </summary>
		public string PortalWebPath
		{
			get
			{
				string myPortalWebPath = Settings.Path.WebPathCombine(Settings.Path.ApplicationRoot, _portalPath,StStr.ModulesLayoutPrivateFolder);
				return myPortalWebPath;
			}
		}

		/// <summary>
		/// The path of the ModulesLayout dir (Physical path)
		/// used ot load Layouts
		/// </summary>
		public static string Path
		{
			get
			{
				return HttpContext.Current.Server.MapPath(WebPath);
			}
		}

		/// <summary>
		/// The path of the current portal ModulesLayout dir (Physical path)
		/// used to load Layouts
		/// </summary>
		public string PortalModulesLayoutPath
		{
			get
			{
				return HttpContext.Current.Server.MapPath(PortalWebPath);
			}
		}
	}
}